﻿using System;
using System.Drawing;
using System.Globalization;
using System.Xml;

using VirtualTournaments.DesktopMatchViewer.Resources;

namespace VirtualTournaments.MatchProvider
{
	public static class MatchProvider
	{
		private static NumberFormatInfo numberFormat;

		private static string[] matchEventLabels = { "falta", "amarilla", "roja", "gol" };

		static MatchProvider()
		{
			numberFormat = new NumberFormatInfo();
			numberFormat.NumberDecimalSeparator = ".";
		}

		// TODO: be aware of errors!
		public static ShowableMatch LoadMatch(XmlDocument sourceDocument)
		{
			// Declare and initialize returning type
			ShowableMatch newMatch;
			XmlNode matchNode = sourceDocument.SelectSingleNode("partido");
			XmlAttributeCollection matchAttributes = matchNode.Attributes;
			string matchDate = matchAttributes.GetNamedItem("fecha").Value;
			long matchHalfCicles = Convert.ToInt64(matchAttributes.GetNamedItem("ticksPorTiempo").Value);
			float fBallDiameter = float.Parse(matchAttributes.GetNamedItem("diametroPelota").Value, numberFormat);
			float fParticipantDiameter = float.Parse(matchAttributes.GetNamedItem("diametroJugador").Value, numberFormat);
			int ballDiameter = Convert.ToInt32(fBallDiameter * 10);
			int participantDiameter = Convert.ToInt32(fParticipantDiameter * 10);
			newMatch = new ShowableMatch(matchDate, matchHalfCicles, ballDiameter, participantDiameter);

			// Get teams in match
			XmlNodeList teamsNode = matchNode.SelectNodes("equipo");
			setMatchTeams(newMatch, teamsNode);

			// Declare and initialize match ball
			ShowableParticipant matchBall;
			Bitmap ballImage = Images.Ball;
			matchBall = new ShowableParticipant(ballImage, newMatch.ballSize);
			newMatch.setMatchBall(matchBall);

			// Get first half cicles
			XmlNode halfCiclesNode = matchNode.SelectSingleNode("primertiempo");
			XmlNodeList halfCicles = halfCiclesNode.SelectNodes("tick");
			addTicks(halfCicles, newMatch);

			// Get first second cicles
			// TODO: think of a better way to do this!
			halfCiclesNode = matchNode.SelectSingleNode("segundotiempo");
			halfCicles = halfCiclesNode.SelectNodes("tick");
			addTicks(halfCicles, newMatch);

			return newMatch;
		}

		private static void addTicks(XmlNodeList xHalfCicles, ShowableMatch xMatch)
		{
			string eventDescription = string.Empty, teamInEvent = string.Empty;
			long cicle = 0;
			int participantInEvent = 0;

			int participantDisplacement = (xMatch.participantSize / 2);
			int ballDisplacement = (xMatch.ballSize / 2);

			// Navigate tick nodes
			foreach (XmlNode tickNode in xHalfCicles)
			{

				string teamID;
				int participantIndex, participantXPosition = 0, participantYPosition = 0, ballXPosition = 0, ballYPosition = 0;
				float fParticipantXPosition, fParticipantYPosition, fBallXPosition, fBallYPosition;
				ShowableTeam team;
				XmlNodeList teams = tickNode.SelectNodes("equipo");

				// Navigate teams in node
				foreach (XmlNode teamNode in teams)
				{
					teamID = teamNode.Attributes.GetNamedItem("id").Value;

					// Navigate participant movements in node
					XmlNodeList participantMovements = teamNode.SelectNodes("jugador");
					foreach (XmlNode participantNode in participantMovements)
					{
						// Get participant info: index, x position and y position
						participantIndex = Convert.ToInt32(participantNode.Attributes.GetNamedItem("nro").Value);
						fParticipantXPosition = float.Parse(participantNode.SelectSingleNode("x").InnerText, numberFormat);
						fParticipantYPosition = float.Parse(participantNode.SelectSingleNode("y").InnerText, numberFormat);

						// Convert positions to fit default size (300x200) and reverse y position to start bottom left
						participantXPosition = Math.Abs(Convert.ToInt32(fParticipantXPosition * 10) - participantDisplacement);
						participantYPosition = Math.Abs(Convert.ToInt32(fParticipantYPosition * 10) - (200 - participantDisplacement));

						team = xMatch.getTeamByID(teamID);
						team.addParticipantPosition(participantIndex, new Point(participantXPosition, participantYPosition));

					}
				}

				// Get ball info
				XmlNode matchBallNode = tickNode.SelectSingleNode("pelota");
				fBallXPosition = float.Parse(matchBallNode.SelectSingleNode("x").InnerText, numberFormat);
				fBallYPosition = float.Parse(matchBallNode.SelectSingleNode("y").InnerText, numberFormat);

				ballXPosition = Math.Abs(Convert.ToInt32(fBallXPosition * 10) - ballDisplacement);
				ballYPosition = Math.Abs(Convert.ToInt32(fBallYPosition * 10) - (200 - ballDisplacement));

				xMatch.getMatchBall().addPoint(new Point(ballXPosition, ballYPosition));

				XmlNode optionalEventNode;
				foreach (string eventLabel in matchEventLabels)
				{
					optionalEventNode = tickNode.SelectSingleNode(eventLabel);
					if (optionalEventNode != null)
					{
						eventDescription = optionalEventNode.Name;
						cicle = Convert.ToInt64(tickNode.Attributes.GetNamedItem("nro").Value);
						teamInEvent = optionalEventNode.Attributes.GetNamedItem("idEquipo").Value;
						participantInEvent = Convert.ToInt32(optionalEventNode.Attributes.GetNamedItem("nro").Value);
						xMatch.addEvent(new ShowableEvent(cicle, teamInEvent, participantInEvent, eventDescription));
					}
				}
			}
		}

		// Receive a match instance and a team node. Load up the team in the match.
		internal static void setMatchTeams(ShowableMatch xNewMatch, XmlNodeList xTeamsNode)
		{
			ShowableTeam team;
			string teamID, teamName, teamColor;
			foreach (XmlNode teamNode in xTeamsNode)
			{
				teamID = teamNode.Attributes.GetNamedItem("id").Value;
				teamName = teamNode.Attributes.GetNamedItem("nombre").Value;
				teamColor = teamNode.Attributes.GetNamedItem("color").Value;
				team = new ShowableTeam(teamID, teamName, teamColor);

				ShowableParticipant[] teamParticipants = getTeamParticipants(teamNode.SelectNodes("jugador"), teamColor, xNewMatch.participantSize);
				team.setParticipants(teamParticipants);

				xNewMatch.addTeam(team);
			}
		}

		// Receive a node list of participants and a color to initialize them. Returns the list in as an array of ShowableParticipant
		internal static ShowableParticipant[] getTeamParticipants(XmlNodeList xXmlNodeList, string xTeamColor, int xParticipantSize)
		{
			Bitmap participantImage = getParticipantImage(xTeamColor);
			ShowableParticipant participant;
			ShowableParticipant[] participants = new ShowableParticipant[5];
			int index = 0;
			foreach (XmlNode participantNode in xXmlNodeList)
			{
				string particpantName = participantNode.InnerText;
				participant = new ShowableParticipant(particpantName, participantImage, xParticipantSize);
				participants[index] = participant;
				index++;
			}
			return participants;
		}

		// Receive a team color and return a xTeamColor circle bitmap
		// TODO: this should not be here!
		internal static Bitmap getParticipantImage(string xTeamColor)
		{
			switch (xTeamColor)
			{
				case "rojo": return Images.RedCircle;
				case "azul": return Images.BlackCircle;
				case "negro": return Images.BlackCircle;
				case "blanco": return Images.WhiteCircle;
				case "celeste": return Images.LightBlueCircle;
				case "verde": return Images.GreenCircle;
				default: return Images.BlackCircle;
			}
		}

	}
}
